/////////////////////////////////////////////////////////////////////
//
//  Tackle - A Scrum Tracking Web Site Solution
//  Original Copyright ?2007 Microsoft Corp.  All rights reserved.
//  Released under Microsoft Permissive License (Ms-PL)
//  http://www.codeplex.com/Tackle/Project/License.aspx
//
/////////////////////////////////////////////////////////////////////

// we have some test code in here, use this to turn it off and on
//#define Tackle_Test_Mode

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
using System.Web.Configuration;
using System.Collections.Specialized;

public partial class MasterPage : System.Web.UI.MasterPage
{
    // public accessors to the drop down for scrum teams
    public string ScrumTeamID
    {
        get
        {
            return ddScrumTeam.SelectedValue;
        }
    }

    public string ScrumTeamName
    {
        get
        {
            return ddScrumTeam.SelectedItem.Text;
        }
    }

    public ScriptManager ScriptMgr
    {
        get
        {
            return this.ScriptManagerMain;
        }
    }

    // authorization levels
    public enum UserRole
    {
        Unauthorized = 0,
        Administrator = 1,
        ScrumMaster = 2,
        User = 3,
        ReadOnly = 4
    }

    protected void Page_PreRender(object sender, EventArgs e)
    {
        // if this is the first time we've been here, try and get
        // the users default scrum team
        // otherwise everything should just be set properly

#if Tackle_Test_Mode

        // reauthorize the user if debug info exists as query string
        if (!IsPostBack && Request.Url.ToString().IndexOf('?') >= 0)
        {
            Session["RoleID"] = null;
        }
#endif

        if (Session["RoleID"] == null)
        {
            // if error occurs during authorization, user will be redirected to error page
            if (AuthorizeUser() != TackleError.ErrorCode.NoError)
            {
                return;
            }
        }
        // modify menu items according to the user's role
        UpdateMenuForRole(MainMenu.Items);

        try
        {
            // now use the session variable to set the drop down.
            ddScrumTeam.DataBind();
            ddScrumTeam.SelectedValue = Session["ScrumTeamID"].ToString();
            if (ddScrumTeam.Items.Count <= 1)
            {
                ddScrumTeam.Visible = lblScrumTeam.Visible = false;
            }
        }
        catch (Exception)
        {
            // the user doesn't exist...
            TackleError.SiteAccessDenied();
        }

        // display the info to the user
        string UserName = Page.User.Identity.Name.Substring(Page.User.Identity.Name.IndexOf("\\") + 1);
        lblWelcomeUser.Text = String.Format("Welcome: <b>{0}</b> as <b>{1}</b>", UserName, ((UserRole)Session["RoleID"]).ToString());

        // check if user has access to the requested page
        string url = Request.Url.ToString();
        if (!AuthorizeUserForPage(url))
        {
            TackleError.PageAccessDenied();
        }
    }

    protected void ddScrumTeam_SelectedIndexChanged(object sender, EventArgs e)
    {
        // Set the scrum team preferences for the site
        SetScrumTeamPrefs(Convert.ToInt32(ddScrumTeam.SelectedValue));

        // reset RoleID so that authorization is performed for selected scrum team
        Session["RoleID"] = null;
    }

    private void SetScrumTeamPrefs(int scTeamID)
    {
        // This sets the variables inspite of the permissions a user has
        // If the user doesn't have access to the team, these vars will remain set
        // But will get updated as soon as the user changes to a different team.

        if (scTeamID > 0)
        {
            // set the session state
            Session.Add("ScrumTeamID", scTeamID.ToString());
            // get the hours/week info for the scrum team master backlog
            Session.Add("MBTimeMult", TackleUtility.ShowMasterBacklogInWeeks(scTeamID.ToString()));
            // get the hours/day info for the scrum team sprint backlog
            Session.Add("SBTimeMult", TackleUtility.ShowSprintBacklogInDays(scTeamID.ToString()));
        }
    }

    protected struct PageAuthorizationData
    {
        public string pageName;
        public bool bUser;
        public bool bScrumMaster;
        public bool bReadonly;
        public PageAuthorizationData(string name, bool user, bool master, bool rouser) { pageName = name; bUser = user; bScrumMaster = master; bReadonly = rouser; }
    };

    // tells if the user with current role has access to given URL
    protected bool AuthorizeUserForPage(string url)
    {
        // admin has access to all pages
        if ((UserRole)Session["RoleID"] == UserRole.Administrator)
        {
            return true;
        }

        // extract page name from URL
        string page = url.Substring(url.LastIndexOf("/") + 1);
        if (page.IndexOf("?") >= 0)
        {
            page = page.Substring(0, page.IndexOf("?"));
        }

        // every authenticated user has access to default and error page.
        if (String.Compare(page, "Default.aspx", true) == 0 || String.Compare(page, "Error.aspx", true) == 0)
        {
            return true;
        }

        // check if the user has access to the requested page
        PageAuthorizationData[] padArray = 
        {
            new PageAuthorizationData("AddBacklogItemsToSprint.aspx",   false, true, false),
            new PageAuthorizationData("Admin_ScrumTeams.aspx",          false, false, false),
            new PageAuthorizationData("Admin_SprintMaintenance.aspx",   false, false, false), // disabling scrummaster access to this page...?
            new PageAuthorizationData("Admin_UserPermission.aspx",      false, false, false),
            new PageAuthorizationData("Admin_Users.aspx",               false, false, false),
            new PageAuthorizationData("BurnDownGraph.aspx",             true, true, true),
            new PageAuthorizationData("ChangeList.aspx",                true, true, true),
            new PageAuthorizationData("CompleteSprint.aspx",            false, true, false),
            new PageAuthorizationData("CrossScrumTeamReport.aspx",      true, true, true),
            new PageAuthorizationData("CrossScrumTeamReport_AllSprints.aspx", true, true, true),
            new PageAuthorizationData("DailyScrumEntry.aspx",           true, true, false),
            new PageAuthorizationData("EditSprintBacklog.aspx",         false, true, false),
            new PageAuthorizationData("GenerateSprintBacklog.aspx",     false, true, false),
            new PageAuthorizationData("MasterBacklog.aspx",             false, true, false),
            new PageAuthorizationData("MasterBacklogReport.aspx",       true, true, true),
            new PageAuthorizationData("PersonalStatus.aspx",            true, true, false),
            new PageAuthorizationData("ProductBacklogEntry.aspx",       true, true, false),
            new PageAuthorizationData("ProductEntry.aspx",              true, true, false),
            new PageAuthorizationData("RetrospectiveNotes.aspx",        false, true, false),
            new PageAuthorizationData("ScrumScheduleEntry.aspx",        false, true, false),
            new PageAuthorizationData("SprintResourceEntry.aspx",       false, true, false),
            new PageAuthorizationData("SprintReview.aspx",              true, true, true),
            new PageAuthorizationData("SprintTasksReport.aspx",         true, true, true),
            new PageAuthorizationData("SprintTotals.aspx",              true, true, true),
            new PageAuthorizationData("WeeklyStatus.aspx",              true, true, true),
            new PageAuthorizationData("WeeklyStatusTeamRollup.aspx",    true, true, true),
            new PageAuthorizationData("WorkPerDay.aspx",                true, true, true),
        };

        // go through the page authrization definitions and see if there's a match
        foreach (PageAuthorizationData pad in padArray)
        {
            if (String.Compare(pad.pageName, page, true) == 0)
            {
                // return authorization result depending on the user's role.
                switch ((UserRole)Session["RoleID"])
                {
                    case UserRole.ScrumMaster:
                        return pad.bScrumMaster;

                    case UserRole.User:
                        return pad.bUser;

                    case UserRole.ReadOnly:
                        return pad.bReadonly;

                    default:
                        return false; // should never happen
                };
            }
        }
        return false;
    }

    protected void UpdateMenuForRole(MenuItemCollection menuItems)
    {
        // traverse the menu tree and disable the menu items for the unauthorized pages
        foreach (MenuItem childItem in menuItems)
        {
            UpdateMenuForRole(childItem.ChildItems);
            string url = childItem.NavigateUrl;
            if (!string.IsNullOrEmpty(url) && !AuthorizeUserForPage(url))
            {
                childItem.Enabled = false;
            }
        }
    }

    protected override void OnInit(EventArgs e)
    {
        // Redirect to error page if session has expired
        // If the session is new but there's ASP.NET_SessionId cookie, the session has expired
        if (Session["Session"] == null)
        {
            Session["Session"] = 1;
            string cookieHeader = Page.Request.Headers["Cookie"];
            if (null != cookieHeader && cookieHeader.IndexOf("ASP.NET_SessionId") >= 0)
            {
                TackleError.SessionTimeOut();
            }
        }
    }

    protected TackleError.ErrorCode AuthorizeUser()
    {
        TackleError.ErrorCode errorCode = TackleError.ErrorCode.NoError;
        string errorInfo = "";
        int scTeamID = 0;
        object obj = null;

        // first set the user role as unauthorized
        Session["RoleID"] = UserRole.Unauthorized;
        string UserName = Page.User.Identity.Name.Substring(Page.User.Identity.Name.IndexOf("\\") + 1);


#if Tackle_Test_Mode
            // change user name if it's specified in the querystring.
            {
                NameValueCollection col = Request.QueryString;
                foreach (string key in col.Keys)
                {
                    foreach (string value in col.GetValues(key))
                    {
                        if (String.Compare(key, "User", true) == 0)
                        {
                            UserName = value;
                        }
                    }
                }
            }
            int prevUserID = 0;
            if (Session["UserID"] != null)
            {
                prevUserID = (int)Session["UserID"];
            }
#endif

        // get user ID
        SqlParameter[] sqlParamsUserID = new SqlParameter[] {
                        new SqlParameter("@UserName", UserName)
                };

        // Call through to the user ID from the user logging in. 
        object result = TackleUtility.CallStoredProc("GetUserIDFromUserName", sqlParamsUserID, null, TackleUtility.SProcReturnValue.ScalarValue);
        if (result != null)
        {
            Session["UserID"] = (int)result;
        }
        else
        {
            // the user doesn't exist, so we can 
            // try the guest account and see if it's valid... 
            // it might not exist if the admin disabled it
            UserName = "Guest";
            SqlParameter[] sqlParamsGuest = new SqlParameter[] {
                        new SqlParameter("@UserName", UserName)
                };
            result = TackleUtility.CallStoredProc("GetUserIDFromUserName", sqlParamsGuest, null, TackleUtility.SProcReturnValue.ScalarValue);
            if (result != null)
            {
                Session["UserID"] = (int)result;
            }
        }

#if Tackle_Test_Mode
            // if debug feature specifies new user, get scrum team ID for the new user.
            if (Session["UserID"] != null)
            {
                if ((int)Session["UserID"] != prevUserID)
                {
                    Session["ScrumTeamID"] = null;
                }
            }
#endif

        if (Session["ScrumTeamID"] == null)
        {
            // look up the default Scrum Team for the User
            // setup the command
            SqlParameter[] sqlParamsScrumTeam = new SqlParameter[] {
                        new SqlParameter("@UserName", UserName)
                };

            obj = TackleUtility.CallStoredProc("GetDefaultScrumTeamForUser", sqlParamsScrumTeam, null, TackleUtility.SProcReturnValue.ScalarValue);
            Session.Add("ScrumTeamID", obj);
            if (obj != null)
            {
                scTeamID = (int)obj;
            }
        }
        else
        {
            scTeamID = Convert.ToInt32(Session["ScrumTeamID"]);
        }

        // set the prefs for the new scrum team
        SetScrumTeamPrefs(scTeamID);

        // Get the permission level for the user based on the scrum team chosen
        SqlParameter[] sqlParamsPermLevel = new SqlParameter[] {
                        new SqlParameter("@UserName", UserName),
                        new SqlParameter("@ScrumTeamID", scTeamID)
                };

        obj = TackleUtility.CallStoredProc("GetPermissionLevelForUserInScrumTeam", sqlParamsPermLevel, null, TackleUtility.SProcReturnValue.ScalarValue);
        if (obj != null)
        {
            Session["RoleID"] = (UserRole)obj;
        }
        else
        {
            // the user isn't registered in the database.
            errorCode = TackleError.ErrorCode.SiteAccessDenied;
        }

#if Tackle_Test_Mode
            // change role if it's specified in the querystring
            // or throw an exception if specified to do so
            {
                NameValueCollection col = Request.QueryString;
                foreach (string key in col.Keys)
                {
                    foreach (string value in col.GetValues(key))
                    {
                        if (String.Compare(key, "Role", true) == 0)
                        {
                            Session["RoleID"] = (UserRole)Convert.ToInt32(value);
                        }
                        else if (String.Compare(key, "Exception", true) == 0)
                        {
                            throw new Exception();
                        }
                    }
                }
            }
#endif

        // there was an error. Jump to the error page with appropriate message
        switch (errorCode)
        {
            case TackleError.ErrorCode.SiteAccessDenied:
                TackleError.SiteAccessDenied();
                break;
            case TackleError.ErrorCode.CustomErrorMessage:
                TackleError.CustomErrorMessage(errorInfo);
                break;
        }

        return errorCode;
    }

    protected void Label1_PreRender(object sender, EventArgs e)
    {
        // Read the version number from the web.config file and display it
        hlChangeListVersion.Text = ConfigurationManager.AppSettings["TackleVersion"].ToString(); // "Version 01.00.06.0422 (TnT Production)";
    }


    protected void hypHelp_PreRender(object sender, EventArgs e)
    {
        // as we go to render this hyperlink each time,
        // grab the filename of the new URL and get it ready for help...
        string URL = Request.Url.AbsoluteUri;
        string PageName = URL.Substring(URL.LastIndexOf("/") + 1);
        PageName = PageName.Substring(0, PageName.LastIndexOf(".aspx"));

        // make sure we are showing it... 
        hypHelp.Visible = true;

        // hide the help link for certain pages that don't have help
        switch (PageName)
        {
            case "ChangeList":
                hypHelp.Visible = false;
                break;
        }

        // now set up the URL. 
        hypHelp.NavigateUrl = URL.Substring(0, URL.LastIndexOf("/")) + "/help/" + PageName + "_help.htm";
    }
}
